package io

import java.io.{BufferedWriter, File, FileWriter}
import java.text.SimpleDateFormat

import scala.annotation.tailrec
import scala.io.Source

/**
  * author: HuaZhe Ray
  *
  * describe:   计算服务调用平均时长
  *
  * createDate: 2017/12/15
  * createTime: 10:57
  *
  */
object AverageService {

  type TIME = String
  type THREAD = String
  type SERVICE = String
  type WAYS = String
  type METHOD = String
  val sdf = new SimpleDateFormat("MM-dd hh:mm:ss SSS")
  val regex =  """(\d{2}-\d{2} \d{2}:\d{2}:\d{2} \d{3}) ([^\s]+) DEBUG ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) (.+)""".r


  def main(args: Array[String]): Unit = {
    //    服务调用次数
    countByServiceName


    Thread.sleep(1000)

    //    服务调用时长
    analyzeAverageTime
  }






  /**
    *  最新优化，求服务调用次数  根据 带有request单词的作为一次服务，并过滤掉 INFO 日志， 取 DEBUG 日志
    *  2017-12-14 14:50
    */
  def countByServiceName(): Unit = {

    val source = Source.fromFile("E:\\scala\\detail-test.log", "UTF-8")

    val lists:List[(String,String,String,String,String)] = source.getLines().collect{
      case regex(timestamp, thread,c,service,version,method,requests) => (timestamp,thread,service,method,requests)
    }.toList

    val requests:List[(String,String,String)] = lists.filter(_._5.contains("request")).map (line =>{
      (line._1,line._2,line._3+"."+line._4)
    })

    val countByServiceName:Map[String,Int] = requests.map((_, 1)).groupBy(_._1._3).map(t=>(t._1,t._2.size))

    countByServiceName.foreach {
      case (service, count) => println(s"$service count:$count")
    }


  }




  /**
    * 2017-12-15 统计服务调用平均时长
    *
    * 思路，根据正则 截取到 request 和 response 的 服务 ，然后根据时间排序  ---> 每次调用的 response - request 得到 服务调用时长
    */
  def analyzeAverageTime(): Unit = {
    val source = Source.fromFile("E:\\scala\\detail-test.log", "UTF-8")

    val lists:List[(TIME,THREAD,SERVICE,METHOD,WAYS)] = source.getLines().collect{
      case regex(timestamp, thread,c,service,version,method,requests) => (timestamp,thread,service,method,requests)
    }.toList

    val requests:List[(TIME,THREAD,SERVICE,WAYS)] = lists.filter(_._5.contains("request")).map (line =>{
      (line._1,line._2,line._3+"."+line._4,"request")
    })

    val response:List[(TIME,THREAD,SERVICE,WAYS)] = lists.filter(_._5.contains("response")).map (line =>{
      (line._1,line._2,line._3+"."+line._4,"response")
    })
    //    得到所有 request  和 response 结果
    val totalServices = (requests ++ response).sortWith((t1,t2) => t1._1 < t2._1).take(10)

    //具体进行处理
    processByTailRec(totalServices,Map[(THREAD,SERVICE),TIME]())
  }



  /**
    * 通过定义 mutable Map  来 存放 foreach 临时变量， 进行相减操作
    * @param array
    */
  def process(array:List[(TIME,THREAD,SERVICE,WAYS)]): Unit = {
      val pendings = collection.mutable.Map[(THREAD,SERVICE),TIME]()

      array.foreach{
        case (time,thread,service,ways) => if(ways=="request") {
          pendings += (thread,service) -> time
        }
        else {

          pendings.get((thread,service)) match {
            case Some(time0) => val msg = s"Thread: ${thread} Service: ${service}  average-time:     ${BigDecimal(sdf.parse(time).getTime - sdf.parse(time0).getTime)} ms"
                                pendings.remove((thread, service))
                                writeLogToFile(msg) ; println(msg)
            case None => println("nothing")
          }
        }
      }
  }

  /**
    * 使用尾递归的方法，消除 var 和 mutable Map
    * @param array
    * @param pendings
    */
  @tailrec
  def processByTailRec(array:List[(TIME,THREAD,SERVICE,WAYS)],pendings:Map[(THREAD,SERVICE),TIME]): Unit ={

      array match {
          case (time,thread,service,"response") :: tail =>
              pendings.get((thread, service)) match {

                        case Some(time0) =>
                                        val msg = s"Thread: ${thread} Service: ${service}  average-time:     ${BigDecimal(sdf.parse(time).getTime - sdf.parse(time0).getTime)} ms"
                                                  writeLogToFile(msg) ; println(msg)

                                    processByTailRec(tail, pendings - ((thread, service)))

                        case None =>
                                    processByTailRec(tail, pendings)
          }

          case (time, thread, service, "request") :: tail =>
                processByTailRec(tail, pendings + ((thread, service) -> time) )

          case Nil => None
    }
  }


  /**
    * 写文件
    * @param args
    */
  def writeLogToFile(args:String): Unit ={

    val fw = new FileWriter(new File("E:\\scala\\service_average.log"),true)
    //写入中文字符时会出现乱码
    val bw = new BufferedWriter(fw)
    bw.write(args + "\r\n")
    bw.close()
    fw.close()
  }
}



